package com.company.nuwa.common.utils;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ObjectUtil;
import com.company.nuwa.common.enumration.GraphTimeTypeEnum;
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static java.util.Calendar.*;

/**
 * <p>日期工具类</p>
 *
 * @author lili
 * @version 1.0: DateUtil.java
 * @date 2024/1/27 14:26
 */
public class DateUtil {

    public static final String START_DATE = "startDate";
    public static final String END_DATE = "endDate";
    static final private String DATE_FORMAT = "yyyyMMdd";
    static final private String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    static final private String DEFAULT_DATETIME_FORMAT1 = "yyyyMMdd HH:mm:ss";
    static final private String DEFAULT_DATETIME_SHORT16_FORMAT = "yyyy-MM-dd HH:mm";
    static final private String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    static final private String DEFAULT_MONTH_FORMAT = "yyyy-MM";
    static final private String TIME_FORMAT = "HHmmss";

    /**
     * 获取当前日期 yyyyMMdd
     *
     * @return
     */
    public static String CurrentDate() {
        return getCurrentDateTime(DATE_FORMAT);
    }

    /**
     * 获取当前时间
     *
     * @param fmt 输出格式
     * @return
     */
    public static String getCurrentDateTime(String fmt) {
        if (fmt == null) {
            fmt = DEFAULT_DATETIME_FORMAT;
        }
        return getDateTime(null, fmt);
    }

    /**
     * 根据 毫秒数及格式化信息，输入当前时间
     *
     * @param time
     * @param fmt
     * @return
     */
    public static String getDateTime(Long time, String fmt) {
        if (fmt == null) {
            fmt = DEFAULT_DATETIME_FORMAT;
        }
        if (time != null) {
            return new DateTime(time).toString(fmt);
        } else {
            return new DateTime().toString(fmt);
        }
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static String CurrentTime() {
        return getDateTime(null, TIME_FORMAT);
    }

    public static Date LocalDateToUdate(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        Date date = Date.from(instant);
        return date;
    }

    /**
     * 获取昨天的日期，返回的是 yyyyMMdd
     *
     * @return
     */
    public static String Yesterday() {
        return new DateTime().minusDays(1).toString(DATE_FORMAT);
    }

    /**
     * 间隔天数
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static Long between(Long startTime, Long endTime) {
        return Math.abs(startTime / (24 * 60 * 60 * 1000) - endTime / (24 * 60 * 60 * 1000));
    }

    /**
     * 判断是否是今天的日期
     *
     * @param time
     * @return
     */
    public static Boolean checkToday(Long time) {
        return getDateTime(time, "yyyy-MM-dd").equals(getCurrentDate());
    }

    /**
     * 获取当前日期
     *
     * @return
     */
    public static String getCurrentDate() {
        return getCurrentDateTime(DEFAULT_DATE_FORMAT);
    }

    /**
     * 判断是否是昨天的日期
     *
     * @param time
     * @return
     */
    public static Boolean checkYesterday(Long time) {
        return getDateTime(time, "yyyy-MM-dd") == getYesterday();
    }

    /**
     * 获取昨天的日期，返回的是 yyyy-MM-dd
     *
     * @return
     */
    public static String getYesterday() {
        return new DateTime().minusDays(1).toString(DEFAULT_DATE_FORMAT);
    }

    /**
     * 开始日期与结束日期的每个日期
     */
    public static List<String> findDates(Date dBegin, Date dEnd) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        List<String> lDate = new ArrayList<>();
        //lDate.add(dBegin);
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        lDate.add(format.format(dBegin.getTime()));
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            String enddate = format.format(calBegin.getTime());
            // System.out.println("=="+enddate);
            lDate.add(enddate);
        }
        return lDate;
    }

    /**
     * 开始日期与结束日期的每个月份
     */
    public static List<String> findYesrs(Date dBegin, Date dEnd) throws ParseException {
        ArrayList<String> result = new ArrayList<String>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");//格式化为年月

        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();

        min.setTime(sdf.parse(sdf.format(dBegin)));
        min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

        max.setTime(sdf.parse(sdf.format(dEnd)));
        max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);

        Calendar curr = min;
        while (curr.before(max)) {
            result.add(sdf.format(curr.getTime()));
            curr.add(Calendar.MONTH, 1);
        }
        return result;
    }

    /**
     * 获取上个月的今天日期
     *
     * @param fmt
     * @return
     */
    public static String getBeforeMonthDate(String fmt) {
        if (fmt == null) {
            fmt = DEFAULT_DATE_FORMAT;
        }
        return new DateTime().minusDays(1).toString(fmt);
    }

    /**
     * 获取前天的日期，返回的是 yyyy-MM-dd
     *
     * @return
     */
    public static String getBeforeYesterday() {
        return new DateTime().minusDays(2).toString(DEFAULT_DATE_FORMAT);
    }

    /**
     * 获取当前年月
     *
     * @return
     */
    public static String getCurrent() {
        return getCurrentDateTime(DEFAULT_MONTH_FORMAT);
    }

    /**
     * 获取今天开始0点时间
     *
     * @return
     */
    public static Long getCurrentDateFirst() {
        return new DateTime().withMillisOfDay(0).getMillis();
    }

    /**
     * 获取今天最后一毫秒时间
     *
     * @return
     */
    public static Long getCurrentDateLast() {
        return new DateTime().withHourOfDay(23).withMinuteOfHour(59).withSecondOfMinute(59)
                .getMillis() + 999;
    }

    /**
     * 获取当前时间，输出格式yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String getCurrentDateTime() {
        return getCurrentDateTime(DEFAULT_DATETIME_FORMAT);
    }

    /**
     * 获取当前毫秒数 yyyy-MM-dd
     *
     * @return
     */
    public static Long getCurrentTime() {
        return System.currentTimeMillis();
    }

    /**
     * 获取当前传入 日期的毫秒
     *
     * @param strDate
     * @return
     */
    public static Long getDate(String strDate) {
        if (strDate != null) {
            return formatDateTime(strDate, null);
        } else {
            return null;
        }
    }

    static Long formatDateTime(String dateTime, String fmt) {
        if (dateTime == null) {
            return null;
        }
        dateTime = dateTime.trim();
        if (fmt == null) {
            switch (dateTime.length()) {
                case 5:
                    // 5位是 MM-dd格式，需要进行补位，默认情况下面，
                    String yyyyMMdd = getDateTime(null, DEFAULT_DATE_FORMAT);
                    String[] cDay = yyyyMMdd.split("-");

                    String[] hDay = dateTime.split("-");
                    // 当前的月份 大于 传入的时间月份的时候，默认设置为 传入的时间是今年
                    if ((Integer.parseInt(cDay[1])) >= (Integer.parseInt(hDay[0]))) {
                        dateTime = cDay[0] + "-" + dateTime;
                    } else { // 反之，传入的时间是去年的
                        dateTime = (Integer.parseInt(cDay[0])) + "-" + dateTime;
                    }
                    fmt = DEFAULT_DATE_FORMAT;
                    break;
                case 8:
                    fmt = DATE_FORMAT;
                    break;
                case 10:
                    fmt = DEFAULT_DATE_FORMAT;
                    break;
                case 16:
                    fmt = DEFAULT_DATETIME_SHORT16_FORMAT;
                    break;
                default:
                    fmt = DEFAULT_DATETIME_FORMAT;
                    break;
            }
        }
        DateTimeFormatter format = DateTimeFormat.forPattern(fmt);
        return DateTime.parse(dateTime, format).getMillis();
    }

    /**
     * 获取当前传入 日期的 00:00:00 毫秒
     *
     * @param strDate 格式 yyyy-MM-dd
     * @return
     */
    public static Long getDateFirst(String strDate) {
        if (strDate != null) {
            if (strDate.length() != 10) {
                return null;
            }
            return formatDateTime(strDate + " 00:00:00", null);
        } else {
            return null;
        }
    }

    /**
     * 获取当前传入 日期的 00:00:00 毫秒
     *
     * @param strDate 格式 yyyyMMdd
     * @return
     */
    public static Long getDateFirst1(String strDate) {
        if (strDate != null) {
            DateTimeFormatter format = DateTimeFormat.forPattern(DEFAULT_DATETIME_FORMAT1);
            return DateTime.parse(strDate + " 00:00:00", format).getMillis();
        } else {
            return null;
        }
    }

    /**
     * 获取当前传入 日期的 00:00:00 毫秒
     *
     * @param strDate 格式 yyyy-MM-dd
     * @return
     */
    public static Long getDateFirsts(String strDate) {
        if (strDate != null) {
            if (strDate.length() != 10) {
                return null;
            }
            return formatDateTime(strDate + " 23:59:59", null);
        } else {
            return null;
        }
    }

    /**
     * 获取当前传入 日期的 23:59:59 毫秒
     *
     * @param strDate 格式 yyyyMMdd
     * @return
     */
    public static Long getDateLast1(String strDate) {
        if (strDate != null) {
            DateTimeFormatter format = DateTimeFormat.forPattern(DEFAULT_DATETIME_FORMAT1);
            return DateTime.parse(strDate + " 23:59:59", format).getMillis();
        } else {
            return null;
        }
    }

    /**
     * 根据 毫秒数格式化日期
     *
     * @return yyyyMMdd
     */
    public static String getDateStr() {
        return getCurrentDateTime(DATE_FORMAT);
    }

    /**
     * 根据 毫秒数格式化日期
     *
     * @param time
     * @param fmt
     * @return
     */
    public static String getDateTimeStr(Long time, String fmt) {
        if (fmt == null) {
            fmt = DEFAULT_DATETIME_FORMAT;
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(fmt);
        if (time != null) {
            return simpleDateFormat.format(time);
        } else {
            return null;
        }
    }

    /**
     * 两个时间相差距离多少天多少小时多少分多少秒
     *
     * @return String 返回值为：xx天xx小时xx分xx秒
     */
    public static String getDistanceTime(long time1, long time2) {

        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;
        try {

            long diff;
            if (time1 < time2) {
                diff = time2 - time1;
            } else {
                diff = time1 - time2;
            }
            day = diff / (24 * 60 * 60 * 1000);
            hour = (diff / (60 * 60 * 1000) - day * 24);
            min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
            sec = (diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String messageTime = "";
        if (day >= 1) {
            messageTime = day + "天前";
        } else if (hour < 24 && hour > 0) {
            messageTime = hour + "小时前";
        } else if (min < 60 && min > 0) {
            messageTime = min + "分钟前";
        } else if (sec < 60) {
            messageTime = "刚刚";
        }
        return messageTime;
        // return day + "天" + hour + "小时" + min + "分" + sec + "秒";
    }

    /**
     * 两个时间相差距离多少天
     */
    public static String getDistanceTimeDay(long time1, long time2) {

        long day = 0;

        try {

            long diff;
            if (time1 < time2) {
                diff = time2 - time1;
            } else {
                diff = time1 - time2;
            }
            day = diff / (24 * 60 * 60 * 1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String messageTime = "1";
        if (day >= 1) {
            messageTime = String.valueOf(day);
        }
        return messageTime;
        // return day + "天" + hour + "小时" + min + "分" + sec + "秒";
    }

    /**
     * 获取指定 时间的下N天
     * 如果 time不传递，将获取今天的下N天
     *
     * @param time
     * @param fmt
     * @return
     * @prarm step
     */
    public static String getNextDate(Long time, String fmt, Integer step) {
        if (fmt == null) {
            fmt = DEFAULT_DATE_FORMAT;
        }

        if (time != null) {
            return new DateTime(time).plusDays(step).toString(fmt);
        } else {
            return new DateTime().plusDays(step).toString(fmt);
        }
    }

    /**
     * 获取指定 时间的下N天，返回毫秒数
     * 如果 time不传递，将获取今天的下N天
     *
     * @param time
     * @return
     * @prarm step
     */
    public static Long getNextDate(Long time, Integer step) {
        if (time != null) {
            return new DateTime(time).plusDays(step).getMillis();
        } else {
            return new DateTime().plusDays(step).getMillis();
        }
    }

    /**
     * 获取当前月日
     *
     * @return
     */
    public static String getNowTime() {
        Calendar now = Calendar.getInstance();
        String time = (now.get(Calendar.MONTH) + 1) + "月" + now.get(Calendar.DAY_OF_MONTH) + "日";
        return time;
    }

    /**
     * 获取上周昨天的日期，返回的是 yyyy-MM-dd
     *
     * @return
     */
    public static String getWeekYesterday() {
        return new DateTime().minusDays(8).toString(DEFAULT_DATE_FORMAT);
    }

    /**
     * 获取昨天的 00:00:00 毫秒
     *
     * @return
     */
    public static Long getYesterdayFirst() {
        return new DateTime().minusDays(1).withMillisOfDay(0).getMillis();
    }

    /**
     * 获取昨天的 23:59:59 毫秒
     *
     * @return
     */
    public static Long getYesterdayLast() {
        return new DateTime().minusDays(1).withHourOfDay(23).withMinuteOfHour(59)
                .withSecondOfMinute(59).getMillis();
    }

    /**
     * 日期格式化成字符串
     *
     * @param date
     * @param fmt
     * @return
     * @throws Exception
     */
    public static Date strFormatDate(String date, String fmt) throws Exception {
        SimpleDateFormat myFormat = new SimpleDateFormat(fmt);
        return myFormat.parse(date);
    }

    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    @SneakyThrows
    public static Map<String, Date> getGraphQueryDate(GraphTimeTypeEnum timeType) {

        Integer offsetValue = timeType.getValue();

        // 统计数据时间范围
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.add(Calendar.DATE, offsetValue);
        startCalendar.set(Calendar.HOUR_OF_DAY, 0);
        startCalendar.set(Calendar.MINUTE, 0);
        startCalendar.set(Calendar.SECOND, 0);
        Calendar endCalendar = Calendar.getInstance();

        if (ObjectUtil.equals(timeType.getCode(), GraphTimeTypeEnum.DAY_YESTERDAY.getCode())) {
            endCalendar.add(Calendar.DATE, offsetValue);
        }
        endCalendar.set(Calendar.HOUR_OF_DAY, 23);
        endCalendar.set(Calendar.MINUTE, 59);
        endCalendar.set(Calendar.SECOND, 59);


        Map<String, Date> map = Maps.newHashMap();
        map.put(START_DATE, startCalendar.getTime());
        map.put(END_DATE, endCalendar.getTime());
        return map;

    }


    /**
     * 获取时间段内月份时间  yyyyMM
     *
     * @param timeType
     * @param offset   偏移量 0当前时间 -1 上月 -2 前月
     * @return
     */
    @SneakyThrows
    public static Map<String, Date> getGraphQueryMonthByOffset(GraphTimeTypeEnum timeType, int offset) {
        Integer offsetValue = timeType.getValue();
        // 统计数据时间范围
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.add(Calendar.MONTH, offsetValue);
        Calendar endCalendar = Calendar.getInstance();

        //偏移量
        startCalendar.add(Calendar.MONTH, offset);
        endCalendar.add(Calendar.MONTH, offset);

        Map<String, Date> map = Maps.newHashMap();
        map.put(START_DATE, startCalendar.getTime());
        map.put(END_DATE, endCalendar.getTime());
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
//        System.out.println("sdf = " + sdf.format(startCalendar.getTime()));
//        System.out.println("sdf = " + sdf.format(endCalendar.getTime()));
        return map;

    }

    /**
     * 获取年份
     *
     * @param date
     * @return
     */
    @SneakyThrows
    public static Integer dateToYear(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy");
        return Integer.valueOf(format.format(date));
    }

    /**
     * 获取年月日
     *
     * @param date
     * @return
     */
    @SneakyThrows
    public static Integer dateToInteger(Date date) {
        if (date != null) {
            SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);
            return Integer.valueOf(format.format(date));
        }
        return null;
    }

    /**
     * 获取某个时间 是第几周
     *
     * @param date
     * @return
     */
    @SneakyThrows
    public static Integer dateToWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(MONDAY);
        calendar.setTime(date);
        Integer weekNumbe = calendar.get(Calendar.WEEK_OF_YEAR);
        return weekNumbe;
    }

    @SneakyThrows
    public static Map<String, Date> getWeekTime(Date date) {
        Map<String, Date> dateMap = new HashMap<>();
        Calendar calendar = getInstance();
        calendar.setFirstDayOfWeek(MONDAY);
        calendar.setTime(date);

        calendar.set(DAY_OF_WEEK, MONDAY);
        setMinTimeOfDay(calendar);
        dateMap.put("startDate", calendar.getTime());

        calendar.set(DAY_OF_WEEK, SUNDAY);
        setMaxTimeOfDay(calendar);
        dateMap.put("endDate", calendar.getTime());
        return dateMap;
    }

    private static void setMinTimeOfDay(Calendar calendar) {
        calendar.set(HOUR_OF_DAY, 0);
        calendar.set(SECOND, 0);
        calendar.set(MINUTE, 0);
        calendar.set(MILLISECOND, 0);
    }

    private static void setMaxTimeOfDay(Calendar calendar) {
        calendar.set(HOUR_OF_DAY, 23);
        calendar.set(SECOND, 59);
        calendar.set(MINUTE, 59);
        calendar.set(MILLISECOND, 999);
    }


    /**
     * 获取当前时间前30分钟时间
     *
     * @return
     */
    public static Date getMinuteAgoTime() {
        Date date = new Date();
        Calendar calendar = getInstance();
        calendar.setTime(date);
        calendar.add(MINUTE, -30);
        return calendar.getTime();
    }

    /**
     * 获取当年的第几周
     * 格式：(yyyy+第几周，不足10补0)
     * 列子：202301,202315
     *
     * @return
     */
    public static Long getWhichWeekOfYear(Date date) {
        cn.hutool.core.date.DateTime startTime = cn.hutool.core.date.DateUtil.beginOfWeek(date);
        int week = cn.hutool.core.date.DateUtil.weekOfYear(startTime);
        String year = cn.hutool.core.date.DateUtil.format(date, DatePattern.NORM_YEAR_PATTERN);
        String whichWeekOfYear = "";
        if (week / 10 < 1) {
            whichWeekOfYear = year + "0" + week;
        } else {
            whichWeekOfYear = year + week;
        }
        return Long.valueOf(whichWeekOfYear);
    }

    /**
     * 获取年度日期
     * 格式：(yyyyMMdd)
     *
     * @return
     */
    public static Long getDateOfYear(Date date) {
        return Long.valueOf(cn.hutool.core.date.DateUtil.format(date, DatePattern.PURE_DATE_PATTERN));
    }

    /**
     * 获取传入日期当天的开始时间
     *
     * @param date
     * @return
     */
    public static Date getDateStartTime(Date date) {
        if (date != null) {
            SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
            String dateStr = format.format(date);
            DateTimeFormatter format1 = DateTimeFormat.forPattern(DEFAULT_DATETIME_FORMAT);
            return new Date(DateTime.parse(dateStr + " 00:00:00", format1).getMillis());
        } else {
            return null;
        }
    }

    /**
     * 获取传入日期当天的结束时间
     *
     * @param date
     * @return
     */
    public static Date getDateEndTime(String date) {
        if (date != null) {
            SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
            String dateStr = format.format(date);
            DateTimeFormatter format1 = DateTimeFormat.forPattern(DEFAULT_DATETIME_FORMAT);
            return new Date(DateTime.parse(dateStr + " 23:59:59", format1).getMillis());
        } else {
            return null;
        }
    }

    /**
     * 转换日期获取最后时间
     *
     * @param date
     * @return
     * @throws ParseException
     */
    @SneakyThrows
    public static Date getDateLastTime(Date date) {
        if (Objects.isNull(date)) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String time = sdf.format(date);
        time += " 23:59:59";
        SimpleDateFormat end = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return end.parse(time);
    }

}
